package classifieurs;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import extraction.Categorie;
import extraction.Tweet;

import tools.FrenchStemmer;
import tools.FrenchTokenizer;
import tools.Normalizer;


/**
 * Cette classe permet de traiter un fichier, en tenant compte de la validation croisée
 *
 */
public class DataClassification {

	/** Fichier stop words (mots non pris en compte lors de la normalisation). */
	//public static String STOP_WORDS = "./motsOutils.txt";
	//public static String STOP_WORDS = "./vide.txt";

	public static String STOP_WORDS = "data/mot_moins_frequents.txt";
	//public static String STOP_WORDS = "./mot_plus_frequents.txt";

	/** Pour 10 tests differents <indice_test, statParClasse> */
	public HashMap<Integer, HashMap<String, Categorie>> mapStatParClass;

	/**
	 * 20 mots significatifs pour chaque polarité
	 * 	rempli dans classifieur correspondant
	 */
	public HashMap<String, ArrayList<String>> mots_significatifs;

	/**
	 * dictionnaire de mots
	 */
	public static ArrayList<String> mots = new ArrayList<String>();

	/**
	 * Cette méthode permet d'extraire toutes les lignes d'un fichiers dans un ArrayList
	 * qui est renvoyé.
	 * @param nomFic : Nom du fichier à extraire.
	 * @return un ArrayList contenant 
	 * @throws IOException 
	 */
	private ArrayList<String> extractionLignesFichier (String nomFic) throws IOException {

		InputStream ips=new FileInputStream(nomFic); 
		InputStreamReader ipsr;

		// Verification du type du fichier
		if ( nomFic.endsWith(".txt")) 
			ipsr=new InputStreamReader(ips);
		else {

			System.err.println("Mauvais type de fichier.");
			return null;
		}

		BufferedReader br=new BufferedReader(ipsr);
		String line;
		ArrayList<String> lignesFichier = new ArrayList<String>();
		// Pour chaque lignes du fichier
		while ((line=br.readLine())!=null){
			// On vérifie si nous avons bien 5 champs sur cette ligne
			if ( 5 == line.split("\",\"").length){
				lignesFichier.add(line);		// Et nous l'insérons dans l'ArrayList
			}
		}

		br.close(); 

		return lignesFichier;
	}

	/**
	 * Méthode qui analyse une ligne passée en parametre afin d'en extraire
	 * les différentes parties d'un message, ainsi que les mots du tweetText.
	 * @param ligne : la ligne à analyser.
	 * @param test 
	 * @throws IOException 
	 */
	private void analyseLigne (String ligne, HashMap<String, Categorie> statsParClasses, boolean test) throws IOException {
		// On découpe les différents champs de la ligne
		String [] tabChamps = ligne.split("\",\"");

		// Si c'est un test
		if (test){		
			tabChamps[1] = "test_"+tabChamps[1]; // on marque les champs de test
		}

		// On enleve le " du début.
		tabChamps[0] = tabChamps[0].substring(1); 
		// On enlève le " de fin.
		tabChamps[4] = tabChamps[4].substring(0, tabChamps[4].length()-1);



		boolean polariteOk = false;

		// On vérifie que la polarité existe dans notre liste
		for (String mot : Categorie.getTypePolarite()){
			if (tabChamps[1].equals(mot)){
				polariteOk = true;
			}
		}

		if (polariteOk){

			// On retire le # ou les @ qui pourraient etre présent
			tabChamps[4] = tabChamps[4].replace("#", "");
			tabChamps[4] = tabChamps[4].replace("@", "");



			// Nous faisons appel au Normalizer du premier projet d'EIT pour recupèrer les mots.
			Normalizer norm = new FrenchTokenizer(STOP_WORDS);

			ArrayList<String> result = norm.normalizeLigne(tabChamps[4], true);

			//on enleve mots significatifs
			if (mots_significatifs != null){
				String polarite = tabChamps[1];
				ArrayList<String> test_mots = new ArrayList<String>();
				if (polarite.equals("positive")){
					test_mots = mots_significatifs.get("positive");				
				}
				else if (polarite.equals("negative")){
					test_mots = mots_significatifs.get("negative");
				}
				else if (polarite.equals("neutral")){
					test_mots = mots_significatifs.get("neutral");
				}
				else if (polarite.equals("irrelevant")){
					test_mots = mots_significatifs.get("irrelevant");
				}

				//si le tweet contient des mots significatifs, on les enleve
				for (String mot : test_mots){
					if  (result.contains(mot))
						result.remove(mot);
				}
			}

			// On extrait les différents champs d'un tweet, puis on l'insère.
			Tweet m = new Tweet(tabChamps[0], tabChamps[1], tabChamps[2], tabChamps[3], tabChamps[4]);
			m.setLongueurMessage(result.size());
			statsParClasses.get(tabChamps[1]).addTweet(m);

			//si pas un test, on ajoute les mots au dico
			if (!test){
				//on remplit la liste de mots au total
				for (String mot : result){
					if (!mots.contains(mot))
						mots.add(mot);
				}

			}
			// Insertion des mots dans la map "mots", en fonction de la polarité
			statsParClasses.get(tabChamps[1]).addListeMotsOcc(result); 	// occurence du mot

			// Insertion des mots dans la map "motsTweet", en fonction de la polarité
			statsParClasses.get(tabChamps[1]).addListeMotsTweet(result); 	// nb de tweet qui comprennent le mot


		}
		else {
			System.err.println("Polarité non existante.");
			return;
		}
	}


	/**
	 * Initialisation de la map qui va stocker les statistiques sur les mots.
	 * @return HashMap<String, Statistique>
	 */
	private HashMap<String, Categorie> initialiseMapStats(){
		HashMap<String, Categorie> statsParClasses = new HashMap<String, Categorie>();

		// Création des types de statistiques
		for (String type : Categorie.getTypePolarite()){
			statsParClasses.put(type, new Categorie(type));
		}
		return statsParClasses;
	}


	/**
	 * Méthode qui permet d'analyser un fichier passé en parametre.
	 * On va y appeler le méthode d'extraction des lignes du fichier, puis traiter
	 * chacunes de ces lignes avec la méthode analyseLigne.
	 * @param nomFic : Fichier à traiter.
	 * @throws IOException 
	 */
	public void analyseFichier (String nomFic) throws IOException {

		mapStatParClass = new HashMap<Integer, HashMap<String,Categorie>>();
		ArrayList<String> lignesFichier;

		// On extrait les lignes du fichier
		lignesFichier = extractionLignesFichier(nomFic);

		// On crée une map qui contiendra les statistiques par classes
		HashMap<String, Categorie> statsParClasses = null ;

		int bloc_size = lignesFichier.size()/10;
		int debut, fin, index, indexMap = 0;
		System.out.println("bloc_size : "+bloc_size);

		for(int i_tweet=0; i_tweet<lignesFichier.size(); i_tweet+=bloc_size){
			statsParClasses = initialiseMapStats();
			debut = i_tweet;
			fin=i_tweet+bloc_size; 
			index=0;
			// Pour chacunes des lignes du fichier, nous allons extraire les mots
			// et les elements du message.
			for (String ligne : lignesFichier) {
				if (index>=debut && index<fin) //bloc test
					analyseLigne (ligne, statsParClasses, true);
				else
					analyseLigne(ligne, statsParClasses, false);
				index++;
			}
			mapStatParClass.put(indexMap, statsParClasses);
			indexMap++;
		}	

	}

	/**
	 * Méthode qui affiche les statistiques pour cette classe.
	 * Cela correspond au nombre total de mots, le nombre de mots différents, 
	 * la longueur moyenne des messages, les 20mots les plus et les moins fréquents
	 * (par la méthode du khi2).
	 */
	public void getStatistiques () {

		double A, B, C, D;
		HashMap <String, Double> khi2; // Contient pour chaque mot d'une classe sa valeur de khi2
		int nbTotalTweet = 0;

		// On recupere le nombre total de tweets (toute classe confondue)
		for (HashMap<String, Categorie> m : mapStatParClass.values()) {

			// Pour chaque classe de polarite
			for (Categorie s : m.values()){
				if (!s.getPolarite().contains("test_")){
					nbTotalTweet += s.getNbTweets();
				}
			}

		}

		// Pour chaque numéro d'index
		for (HashMap<String, Categorie> m : mapStatParClass.values()) {

			// Pour chaque classe de polarite
			for (Categorie s : m.values()){
				// Pour chaque mots de cette classe
				for (Entry<String, Integer> i : s.getMotsOcc().entrySet()){

					A = B = C = D = 0.0;
					// occurence dans la classe courante / occ totale
					A = i.getValue() / getOccTotalMot(i.getKey());
					B = 1 - A;

					C = 0;

				}
			}


		}

	}

	/**
	 * Méthode qui récupère le nombre d'occurences totale dans toutes les classes
	 * de polarité (hormis celles de test).
	 * @param mot
	 * @return
	 */
	public Integer getOccTotalMot(String mot) {

		int nbOccTotal = 0;

		// Pour chaque numéro d'index
		for (HashMap<String, Categorie> m : mapStatParClass.values()) {

			// Pour chaque classe de polarite
			for (Categorie s : m.values()){
				if (!s.getPolarite().contains("test_")){
					nbOccTotal += s.getMotsOcc().get(mot);
				}
			}


		}

		return nbOccTotal;
	}

}
